const { PointTransaction, PointRule, User, SystemLog } = require('../models');
const { AppError } = require('../middlewares/errorHandler');
const { logger } = require('../utils/logger');
const { Op } = require('sequelize');
const sequelize = require('../config/database');

class PointTransactionController {
  /**
   * 创建积分交易
   * @param {Object} ctx - 上下文
   * @returns {Promise<void>}
   */
  async createTransaction(ctx) {
    const { ruleId, userId, description } = ctx.request.body;
    const operatorId = ctx.state.user.id;

    // 开始事务
    const transaction = await sequelize.transaction();

    try {
      // 获取积分规则
      const pointRule = await PointRule.findOne({
        where: {
          id: ruleId,
          status: 'active'
        }
      });

      if (!pointRule) {
        throw new AppError(404, 'Point rule not found or inactive');
      }

      // 检查规则有效期
      const now = new Date();
      if (pointRule.validFrom && pointRule.validFrom > now) {
        throw new AppError(400, 'Point rule is not yet active');
      }
      if (pointRule.validTo && pointRule.validTo < now) {
        throw new AppError(400, 'Point rule has expired');
      }

      // 检查每日限制
      if (pointRule.dailyLimit) {
        const today = new Date();
        today.setHours(0, 0, 0, 0);
        const dailyCount = await PointTransaction.count({
          where: {
            ruleId,
            userId,
            status: 'completed',
            createdAt: {
              [Op.gte]: today
            }
          }
        });
        if (dailyCount >= pointRule.dailyLimit) {
          throw new AppError(400, 'Daily limit exceeded for this rule');
        }
      }

      // 检查每月限制
      if (pointRule.monthlyLimit) {
        const firstDayOfMonth = new Date();
        firstDayOfMonth.setDate(1);
        firstDayOfMonth.setHours(0, 0, 0, 0);
        const monthlyCount = await PointTransaction.count({
          where: {
            ruleId,
            userId,
            status: 'completed',
            createdAt: {
              [Op.gte]: firstDayOfMonth
            }
          }
        });
        if (monthlyCount >= pointRule.monthlyLimit) {
          throw new AppError(400, 'Monthly limit exceeded for this rule');
        }
      }

      // 获取用户
      const user = await User.findByPk(userId);
      if (!user) {
        throw new AppError(404, 'User not found');
      }

      const balanceBefore = user.points;
      const points = pointRule.points;
      let balanceAfter;

      if (pointRule.type === 'spend' && balanceBefore < points) {
        throw new AppError(400, 'Insufficient points balance');
      }

      balanceAfter = pointRule.type === 'earn' ? balanceBefore + points : balanceBefore - points;

      // 创建积分交易
      const pointTransaction = await PointTransaction.create({
        userId,
        ruleId,
        points,
        type: pointRule.type,
        description,
        status: 'completed',
        balanceBefore,
        balanceAfter
      }, { transaction });

      // 更新用户积分
      await user.update({
        points: balanceAfter
      }, { transaction });

      // 记录操作日志
      await SystemLog.create({
        type: 'operation',
        action: 'create_point_transaction',
        userId: operatorId,
        ipAddress: ctx.ip,
        userAgent: ctx.headers['user-agent'],
        description: `Point transaction created: ${pointRule.type} ${points} points for user ${user.username}`
      }, { transaction });

      await transaction.commit();

      ctx.status = 201;
      ctx.body = {
        status: 'success',
        data: { pointTransaction }
      };
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }

  /**
   * 获取积分交易列表
   * @param {Object} ctx - 上下文
   * @returns {Promise<void>}
   */
  async getTransactions(ctx) {
    const { userId, type, status, startDate, endDate } = ctx.query;
    const where = {};

    if (userId) where.userId = userId;
    if (type) where.type = type;
    if (status) where.status = status;
    if (startDate && endDate) {
      where.createdAt = {
        [Op.between]: [new Date(startDate), new Date(endDate)]
      };
    }

    const transactions = await PointTransaction.findAll({
      where,
      include: [
        {
          model: PointRule,
          attributes: ['name', 'type', 'points']
        },
        {
          model: User,
          attributes: ['username', 'email']
        }
      ],
      order: [['createdAt', 'DESC']]
    });

    ctx.body = {
      status: 'success',
      data: { transactions }
    };
  }

  /**
   * 获取单个积分交易
   * @param {Object} ctx - 上下文
   * @returns {Promise<void>}
   */
  async getTransaction(ctx) {
    const { id } = ctx.params;

    const transaction = await PointTransaction.findByPk(id, {
      include: [
        {
          model: PointRule,
          attributes: ['name', 'type', 'points', 'description']
        },
        {
          model: User,
          attributes: ['username', 'email']
        }
      ]
    });

    if (!transaction) {
      throw new AppError(404, 'Transaction not found');
    }

    ctx.body = {
      status: 'success',
      data: { transaction }
    };
  }

  /**
   * 获取用户积分交易列表
   * @param {Object} ctx - 上下文
   * @returns {Promise<void>}
   */
  async getUserTransactions(ctx) {
    const { id } = ctx.params;
    const { type, startDate, endDate } = ctx.query;

    const where = {
      userId: id
    };

    if (type) where.type = type;
    if (startDate && endDate) {
      where.createdAt = {
        [Op.between]: [new Date(startDate), new Date(endDate)]
      };
    }

    const transactions = await PointTransaction.findAll({
      where,
      include: [{
        model: PointRule,
        attributes: ['name', 'type', 'points']
      }],
      order: [['createdAt', 'DESC']]
    });

    ctx.body = {
      status: 'success',
      data: { transactions }
    };
  }

  /**
   * 取消积分交易
   * @param {Object} ctx - 上下文
   * @returns {Promise<void>}
   */
  async cancelTransaction(ctx) {
    const { id } = ctx.params;
    const operatorId = ctx.state.user.id;

    // 开始事务
    const transaction = await sequelize.transaction();

    try {
      const pointTransaction = await PointTransaction.findOne({
        where: { id },
        include: [{ model: PointRule }],
        lock: true,
        transaction
      });

      if (!pointTransaction) {
        throw new AppError(404, 'Transaction not found');
      }

      if (pointTransaction.status !== 'completed') {
        throw new AppError(400, 'Only completed transactions can be cancelled');
      }

      const user = await User.findByPk(pointTransaction.userId, {
        lock: true,
        transaction
      });

      // 反转积分
      const currentBalance = user.points;
      const newBalance = pointTransaction.type === 'earn' 
        ? currentBalance - pointTransaction.points 
        : currentBalance + pointTransaction.points;

      await user.update({
        points: newBalance
      }, { transaction });

      await pointTransaction.update({
        status: 'cancelled'
      }, { transaction });

      // 记录操作日志
      await SystemLog.create({
        type: 'operation',
        action: 'cancel_point_transaction',
        userId: operatorId,
        ipAddress: ctx.ip,
        userAgent: ctx.headers['user-agent'],
        description: `Point transaction cancelled: ${id}`
      }, { transaction });

      await transaction.commit();

      ctx.body = {
        status: 'success',
        message: 'Transaction cancelled successfully'
      };
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }

  /**
   * 获取积分统计
   * @param {Object} ctx - 上下文
   * @returns {Promise<void>}
   */
  async getPointsStatistics(ctx) {
    const { userId, startDate, endDate } = ctx.query;
    const where = {};

    if (userId) where.userId = userId;
    if (startDate && endDate) {
      where.createdAt = {
        [Op.between]: [new Date(startDate), new Date(endDate)]
      };
    }
    where.status = 'completed';

    const stats = await PointTransaction.findAll({
      where,
      attributes: [
        'type',
        [sequelize.fn('COUNT', sequelize.col('id')), 'count'],
        [sequelize.fn('SUM', sequelize.col('points')), 'total']
      ],
      group: ['type']
    });

    ctx.body = {
      status: 'success',
      data: { stats }
    };
  }
}

module.exports = new PointTransactionController(); 